---
title: Code generation
toc_max_heading_level: 6
tags: [codegen, generator, scaffold, template]
---

import VersionLabel from '@site/src/components/Docs/VersionLabel';

Code generation provides an easy mechanism for automating common development workflows and file
structures. Whether it's scaffolding a new library or application, updating configuration, or
standardizing patterns.

To accomplish this, we provide a generator, which is divided into two parts. The first being the
templates and their files to be scaffolded. The second is our rendering engine that writes template
files to a destination.

## Creating a new template

To create a new template, run [`moon generate`][command] while passing the `--template` option. This
will create a template directory and [`template.yml`][config] file in the 1st file-based template
location defined in [`generator.templates`][gen-templates].

```shell
$ moon generate <name> --template
```

### Configuring `template.yml`

Every template requires a [`template.yml`][config] file in the template's directory root. This file
acts as a schema and declares metadata and variables required by the generator.

```yaml title="template.yml"
title: 'npm package'
description: |
  Scaffolds the initial structure for an npm package,
  including source and test folders, a package.json, and more.
variables:
  name:
    type: 'string'
    default: ''
    required: true
    prompt: 'Package name?'
```

### Managing files

Feel free to add any files and folders to the template that you'd like to be generated by consumers!
These files will then be scaffolded 1:1 in structure at the target destination.

An example of the templates folder structure may look something like the following:

```
templates/
├── npm-package/
│   ├── src/
│   ├── tests/
│   ├── package.json
│   └── template.yml
└── react-app/
```

#### Interpolation

Variables can be interpolated into file paths using the form `[varName]`. For example, if you had a
template file `src/[type].ts`, and a variable `type` with a value of "bin", then the destination
file path would be `src/bin.ts`.

This syntax also supports [filters](#filters), such as `[varName | camel_case]`. However, spaces may
cause issues with file path encoding, so this functionality is primarily recommended for the
[`destination`](../config/template#destination) setting.

#### File extensions

To enable syntax highlighting for template engine syntax, you may use the `.tera` (preferred) or
`.twig` file extensions. These extensions are optional, but will be removed when the files are
generated.

Depending on your preferred editor, these extensions may be supported through a plugin, or can be
configured based on file type.

- **VS Code**
  - [Tera extension](https://marketplace.visualstudio.com/items?itemName=karunamurti.tera)
  - [Twig extension](https://marketplace.visualstudio.com/items?itemName=mblode.twig-language-2)
- **Atom**
  - [Twig package](https://atom.io/packages/atom-twig)
- **Webstorm**
  - [Twig plugin](https://plugins.jetbrains.com/plugin/7303-twig)

#### Partials

Partials are special template files that are used for
[composition](https://keats.github.io/tera/docs/#include) and
[inheritance](https://keats.github.io/tera/docs/#inheritance). Because of this, these files _should
not_ be generated into the target destination, and _do not_ support frontmatter.

To ensure they are not generated, include the word "partial" anywhere in the file path. For example,
`partials/header.tpl` or `header.partial.tpl`.

#### Raws<VersionLabel version="1.11.0" />

Raw template files are another special type of file that bypass all Tera rendering, and are used
as-is instead. This is useful for files that contain syntax that conflicts with Tera.

To mark a file as raw, add a `.raw` extension, for example: `file.raw.js` or `file.js.raw`. When the
file is generated, the `.raw` extension will be removed.

#### Frontmatter

Frontmatter is a well-known concept for "per-file configuration", and is achieved by inserting YAML
at the top of the file, delimited by wrapping `---`. This is a very powerful feature that provides
more control than the alternatives, and allows for some very cool integrations.

moon's frontmatter supports functionality like file skipping, force overwriting, and destination
path rewriting.
[View the configuration docs for a full list of supported fields](../config/template#frontmatter).

```twig title="package.json"
---
force: true
---

{
  "name": "{{ name | kebab_case }}",
  "version": "0.0.1"
}
```

Since frontmatter exists in the file itself, you can take advantage of the rendering engine to
populate the field values dynamically. For example, if you're scaffolding a React component, you can
convert the component name and file name to PascalCase.

```twig
{% set component_name = name | pascal_case %}

---
to: components/{{ component_name }}.tsx
---

export function {{ component_name }}() {
  return <div />;
}
```

#### Assets

Assets are binary files that are copied as-is to the destination, without any rendering, and no
support for frontmatter. This applies to all non-text based files, like images, audio, video, etc.

### Template engine & syntax

Rendering templates is powered by [Tera](https://keats.github.io/tera/), a Rust based template
engine with syntax similar to Twig, Liquid, Django, and more. We highly encourage everyone to read
Tera's documentation for an in-depth understanding, but as a quick reference, Tera supports the
following:

- [Variable interpolation](https://keats.github.io/tera/docs/#variables) (defined with the
  [`variables`](../config/template#variables) setting), with
  [built-in filters](https://keats.github.io/tera/docs/#built-in-filters).

```twig
{{ varName }} -> foo
{{ varName | upper }} -> FOO
```

- [Conditional blocks](https://keats.github.io/tera/docs/#if) and
  [loops](https://keats.github.io/tera/docs/#for).

```twig
{% if price < 10 or always_show %}
  Price is {{ price }}.
{% elif price > 1000 and not rich %}
  That's expensive!
{% else %}
  N/A
{% endif %}
```

```twig
{% for item in items %}
  {{ loop.index }} - {{ item.name }}
{% endfor %}
```

- And many more features, like auto-escaping, white space control, and math operators!

#### Filters

Filters are a mechanism for transforming values during interpolation and are written using pipes
(`|`). Tera provides many [built-in filters](https://keats.github.io/tera/docs/#built-in-filters),
but we also provide the following custom filters:

- Strings - `camel_case`, `pascal_case`, `snake_case`, `upper_snake_case`, `kebab_case`,
  `upper_kebab_case`, `lower_case`, `upper_case`

```twig
{{ some_value | upper_case }}
```

- Paths - `path_join`, `path_relative`

```twig
{{ some_path | path_join(part = "another/folder") }}
{{ some_path | path_relative(from = other_path) }}
{{ some_path | path_relative(to = other_path) }}
```

#### Functions

The following functions are available within a template:

- `variables()` - Returns an object containing all variables within the current template.
  <VersionLabel inline version="1.23.0" />

#### Variables

The following variables are always available within a template:

- `dest_dir` - Absolute path to the destination folder.
- `dest_rel_dir` - Relative path to the destination folder from the working directory.
- `working_dir` - Current working directory.
- `workspace_root` - The moon workspace root.

## Generating code from a template

Once a template has been created and configured, you can generate files based on it using the
[`moon generate`][command] command! This is also know as scaffolding or code generation.

This command requires the name of a template as the 1st argument. The template name is the folder
name on the file system that houses all the template files, or the [`id`](../config/template#id)
setting configured in [`template.yml`](../config/template).

```shell
$ moon generate npm-package
```

An optional destination path, relative from the current working directory, can be provided as the
2nd argument. If not provided, the [`destination`](../config/template#destination) setting
configured in [`template.yml`](../config/template) will be used, or you'll be prompted during
generation to provide one.

```shell
$ moon generate npm-package ./packages/example
```

> This command is extremely interactive, as we'll prompt you for the destination path, variable
> values, whether to overwrite files, and more. If you'd prefer to avoid interactions, pass
> `--defaults`, or `--force`, or both.

### Configuring template locations

Templates can be located anywhere, especially when [being shared](#sharing-templates). Because of
this, our generator will loop through all template paths configured in
[`generator.templates`][gen-templates], in order, until a match is found.

```yaml title=".moon/workspace.yml"
generator:
  templates:
    - './templates'
    # Or
    - 'file://other/templates'
```

When using literal file paths, all paths are relative from the workspace root.

#### Archive URLs<VersionLabel version="1.36.0" />

Template locations can reference archives (zip, tar, etc) through https URLs. These archives should
contain templates and will be downloaded and unpacked. The list of
[available archive formats can be found here](https://github.com/moonrepo/starbase/blob/master/crates/archive/src/lib.rs#L76).

```yaml title=".moon/workspace.yml"
generator:
  templates:
    - 'https://domain.com/some/path/to/archive.zip'
```

> Archives will be unpacked to `~/.moon/templates/archive/<host>`, and will be cached for future
> use.

#### Globs<VersionLabel version="1.31.0" />

If you'd prefer more control over literal file paths (above), you can instead use glob paths or the
`glob://` protocol. Globs are relative from the workspace root, and will only match directories, or
patterns that end in `template.yml`.

```yaml title=".moon/workspace.yml"
generator:
  templates:
    - './templates/*'
    # Or
    - 'glob://projects/*/templates/*'
```

#### Git repositories<VersionLabel version="1.23.0" />

Templates locations can also reference templates in an external Git repository using the `git://`
locator protocol. This locator requires the Git host, repository path, and revision (branch, tag,
commit, etc).

```yaml title=".moon/workspace.yml"
generator:
  templates:
    - 'git://github.com/moonrepo/templates#master'
    - 'git://gitlab.com/org/repo#v1.2.3'
```

> Git repositories will be cloned to `~/.moon/templates/git/<host>` using an HTTPS URL (not a Git
> URL), and will be cached for future use.

#### npm packages<VersionLabel version="1.23.0" />

Additionally, template locations can also reference npm packages using the `npm://` locator
protocol. This locator requires a package name and published version.

```yaml title=".moon/workspace.yml"
generator:
  templates:
    - 'npm://@moonrepo/templates#1.2.3'
    - 'npm://other-templates#4.5.6'
```

> npm packages will be downloaded and unpacked to `~/.moon/templates/npm` and cached for future use.

### Declaring variables with CLI arguments

During generation, you'll be prompted in the terminal to provide a value for any configured
variables. However, you can pre-fill these variable values by passing arbitrary command line
arguments after `--` to [`moon generate`][command]. Argument names must exactly match the variable
names.

Using the package template example above, we could pre-fill the `name` variable like so:

```shell
$ moon generate npm-package ./packages/example -- --name '@company/example' --private
```

:::info

- Array variables support multiple options of the same name.
- Boolean variables can be negated by prefixing the argument with `--no-<arg>`.
- Object variables _can not_ declare values through arguments.

:::

## Sharing templates

Although moon is designed for a monorepo, you may be using multiple repositories and would like to
use the same templates across all of them. So how can we share templates across repositories? Why
not try...

- Git submodules
- Git repositories (using `git://` protocol)
- File archives
- Node.js modules
- npm packages (using `npm://` protocol)
- Another packaging system

Regardless of the choice, simply configure [`generator.templates`][gen-templates] to point to these
locations:

```yaml title=".moon/workspace.yml"
generator:
  templates:
    - './templates'
    - 'file://./templates'
    # Git
    - './path/to/submodule'
    - 'git://github.com/org/repo#branch'
    # npm
    - './node_modules/@company/shared-templates'
    - 'npm://@company/shared-templates#1.2.3'
```

### Git and npm layout structure

If you plan to share templates using Git repositories (`git://`) or npm packages (`npm://`), then
the layout of those projects must follow these guidelines:

- A project must support multiple templates
- A template is denoted by a folder in the root of the project
- Each template must have a [`template.yml`][config] file
- Template names are derived from the folder name, or the `id` field in [`template.yml`][config]

An example of this layout structure may look something like the following:

```
<root>
├── template-one/
│   └── template.yml
├── template-two/
│   └── template.yml
├── template-three/
│   └── template.yml
└── package.json, etc
```

These templates can then be referenced by name, such as [`moon generate template-one`][command].

[config]: ../config/template
[command]: ../commands/generate
[gen-templates]: ../config/workspace#templates
